local _G_load = _G.load;
local _G_xpcall = _G.xpcall

local env = dofile("env.lua");
local Element = dofile("Element.lua");
local Component = dofile("Component.lua");
local Window = commonlib.inherit(commonlib.gettable("commonlib.ToolBase"), commonlib.gettable("commonlib.Window"));

Window:Property("RootElement"); -- 根元素
Window:Property("Env"); -- 全局环境
Window:Property("RootPath"); -- 全局环境
Window:Property("Visible", false, "IsVisible"); -- 窗口是否可见
Window:Property("Options");

-- 窗口构造函数
function Window:ctor()
    self.m_url = nil;
    self.m_root_path = nil;
    self:SetEnv(env(self));
    self:SetRootElement(Element:new():Init({name = "document", attr = {style = "width: 100%; height: 100%;"}}, nil, self));
end

-- 窗口初始化
function Window:Init(options)
    self:SetOptions(options or {});
    self:Load();
    return self;
end

-- 加载元素
function Window:Load()
    local root_element = self:GetRootElement();
    local template = self:LoadTemplate();
    local xmlnode = self:LoadXmlFromText(template);
    for _, sub_xmlnode in ipairs(xmlnode) do
        local children = self:LoadChildren(sub_xmlnode, root_element, self);
        root_element:AddChildren(children);
    end
    self:TriggerEventCallBack("load");
end

-- 加载子元素
function Window:LoadChildren(xmlnode, parent, window)
    if (type(xmlnode) == "string") then
        local children = Element:new():Init({name = "text", attr = {text = xmlnode}}, parent, window);
        parent:AddChildren(children);
        return;
    end
    local tagname = xmlnode.name or "div";
    if (tagname == "script") then
        self:LoadScript(xmlnode);
    elseif (tagname == "style") then
        self:LoadStyle(xmlnode, parent, window);
    else
        local children = Element:new():Init(xmlnode, parent, window);
        parent:AddChildren(children);
        for _, sub_xmlnode in ipairs(xmlnode) do self:LoadChildren(sub_xmlnode, children, window); end
    end
end

-- 加载模板
function Window:LoadTemplate()
    local options = self:GetOptions();
    return options.template or commonlib.GetFileText(options.url);
end

-- 加载脚本
function Window:LoadScript(xmlnode)
    local script_text = self:GetXmlNodeText(xmlnode);
    local script_file = xmlnode.attr.src;
    self:DoFile(script_file, nil, self:GetRootPath());
    self:DoString(script_text);
end

-- 加载样式
function Window:LoadStyle(xmlnode, parent, window) end

-- 显示窗口
function Window:Show()
    self:GetRootElement():GetLuaScriptElement():Show();
    self:SetVisible(true);
    self.m_tick_timer = commonlib.SetInterval(1, function() self:OnTick(); end);
end

-- 关闭窗口
function Window:Close()
    self:SetVisible(false);
    if (self:GetRootElement() ~= nil) then self:GetRootElement():GetLuaScriptElement():Close(); end
    commonlib.ClearInterval(self.m_tick_timer);
end

-- 执行脚本
function Window:DoString(script_text, env, script_text_name) commonlib.dostring(script_text, env or self:GetEnv(), script_text_name); end

-- 执行脚本文件
function Window:DoFile(script_file, env) commonlib.dofile(script_file, env or self:GetEnv()); end

function Window:ParseUrl(url)
    local text = commonlib.GetFileText(url);
    local script_text = text;
    local pos = string.find(script_text, "<script[^>]*>");
end

function Window:OnTick()
    if (not self:IsVisible()) then return end

    self.m_nextTickUpdateLayoutElement = self.m_nextTickUpdateLayoutElement or self.m_nextTickUpdateStyleElement;
    if (self.m_nextTickUpdateLayoutElement ~= nil and self.m_nextTickUpdateLayoutElement:IsAncestor(self.m_nextTickUpdateStyleElement)) then
        self.m_nextTickUpdateLayoutElement = self.m_nextTickUpdateStyleElement;
    end

    self.m_nextTickUpdatePositionElement = self.m_nextTickUpdatePositionElement or self.m_nextTickUpdateLayoutElement
    if (self.m_nextTickUpdatePositionElement ~= nil and self.m_nextTickUpdatePositionElement:IsAncestor(self.m_nextTickUpdateLayoutElement)) then
        self.m_nextTickUpdatePositionElement = self.m_nextTickUpdateLayoutElement;
    end

    if (self.m_nextTickUpdateStyleElement) then self.m_nextTickUpdateStyleElement:UpdateStyle(); end

    if (self.m_nextTickUpdateLayoutElement) then self.m_nextTickUpdateLayoutElement:UpdateLayout(); end

    if (self.m_nextTickUpdatePositionElement) then self.m_nextTickUpdatePositionElement:UpdatePosition(); end
end

function Window:UpdateNextTickPositionElement(el)
    if (not self:IsVisible()) then return end
    self.m_nextTickUpdatePositionElement = self.m_nextTickUpdatePositionElement or el;
    if (self.m_nextTickUpdatePositionElement:IsAncestor(el)) then self.m_nextTickUpdatePositionElement = el; end
end

function Window:UpdateNextTickLayoutElement(el)
    if (not self:IsVisible()) then return end
    self.m_nextTickUpdateLayoutElement = el;
    if (self.m_nextTickUpdateLayoutElement:IsAncestor(el)) then self.m_nextTickUpdateStyleElement = el; end
end

function Window:UpdateNextTickStyleElement(el)
    if (not self:IsVisible()) then return end
    self.m_nextTickUpdateStyleElement = self.m_nextTickUpdateStyleElement or el;
    if (self.m_nextTickUpdateStyleElement:IsAncestor(el)) then self.m_nextTickUpdateStyleElement = el; end
end

return Window;
